package com.lqk.nio.zerocopy;

import java.io.FileInputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;

public class NewIOClient {
    public static void main(String[] args) throws Exception {
        InetSocketAddress address = new InetSocketAddress("127.0.0.1", 7001);
        SocketChannel socketChannel = SocketChannel.open();
        socketChannel.connect(address);
        String fileName = "D:\\Progrom Files\\java8new\\netty\\file\\protoc-3.6.1-win32.zip";

        // 得到一个文件Channel
        FileChannel fileChannel = new FileInputStream(fileName).getChannel();

        // 准备发送
        long startTime = System.currentTimeMillis();

        // 在linux下，一个transferTo方法就可以完成传输
        // 在windows下，一次调用transferTo只能发送8M，文件太大的话就需要分段传输文件，并且要注意传输时的位置
        // transferTo底层使用的就是零拷贝
//        long transferCount = fileChannel.transferTo(0, fileChannel.size(), socketChannel);

        /*
            下面代码是解决在windows下，过大文件只能发送8M的问题
            linux 是支持sendFile(零拷贝)，windows不支持，所以底层会进行判断是否符合零拷贝，
            不符合则使用mmap(内存映射)，而mmap(内存映射)的限制MAPPED_TRANSFER_SIZE是8M，
            因此我们使用transferTo方法向socketChannel拷贝数据的时候会限制在8M，
            将sokcetChannel改为Filechannel测试，小于2g是可以一次复制完的。
            底层使用的机制不一致导致的。
         */
        long size = fileChannel.size();
        long position = 0;
        long total = 0;
        while (position < size) {
            long currentNum = fileChannel.transferTo(position, fileChannel.size(), socketChannel);
            System.out.println("复制字节数:"+currentNum);
            if (currentNum <= 0) {
                break;
            }
            total += currentNum;
            position += currentNum;
        }
        System.out.println("发送的总的字节数 ="+total+" 耗时: "+(System.currentTimeMillis()-startTime));

        // 关闭
        fileChannel.close();

    }
}
